home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Testing & Debugging / Audit / Src / LogManager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  17.3 KB  |  666 lines  |  [TEXT/KAHL]

  1. /*                                    LogManager.c                                */
  2. /*
  3.  * LogManager.c
  4.  * Copyright © 1993 Apple Computer Inc. All rights reserved.
  5.  *
  6.  * These functions manage a logging display for error messages and other text.
  7.  * The log is implemented as a ListManager list that can hold nLogItems. This
  8.  * module is intentionally more-or-less self-contained so it can easily be
  9.  * exported to other applications.
  10.  */
  11. #include "LogManager.h"
  12. #include <Packages.h>
  13. /*
  14.  * There is a 32000 byte maximum for the list, so don't
  15.  * make nLogLines too big.
  16.  */
  17. #ifndef nDefaultLogLines
  18. #define nDefaultLogLines    128
  19. #endif
  20. #define width(r)                ((r).right - (r).left)
  21. #define height(r)                ((r).bottom - (r).top)
  22. #ifndef TRUE
  23. #define TRUE                    1
  24. #define FALSE                    0
  25. #endif
  26. enum {
  27.     kScrollBarWidth     = 16,
  28.     kScrollBarOffset    = kScrollBarWidth - 1,
  29.     kActiveControl        = 0,        /* Normal button hilite                */
  30.     kDisabledControl    = 255        /* Disabled button hilite            */
  31. };
  32. /*
  33.  * When the horizontal scrollbar is at zero, the list is indented +4 pixels.
  34.  * When the horizontal scrollbar increases, the list indent decreases. This
  35.  * value is "by inspection," but we could extract it from the list record
  36.  * when the list is initially created.
  37.  */
  38. enum {
  39.     kZeroIndent            = 4
  40. };
  41. /*
  42.  * This sets a nominal value for the maximum cell width. This might be
  43.  * better provided as a user-settable parameter.
  44.  */
  45. #define kMaxHorizontalScroll    (CharWidth('M') * 255)
  46.  
  47. /*
  48.  * Cheap 'n dirty pascal string copy routine.
  49.  */
  50. #ifndef pstrcpy
  51. #define pstrcpy(dst, src) do {                            \
  52.         StringPtr    _src = (src);                        \
  53.         BlockMove(_src, dst, _src[0] + 1);                \
  54.     } while (0)
  55. #endif
  56. /*
  57.  * Cheap 'n dirty pascal string concat.
  58.  */
  59. #ifndef pstrcat
  60. #define pstrcat(dst, src) do {                            \
  61.         StringPtr        _dst = (dst);                    \
  62.         StringPtr        _src = (src);                    \
  63.         short            _len;                            \
  64.         _len = 255 - _dst[0];                            \
  65.         if (_len > _src[0]) _len = _src[0];                \
  66.         BlockMove(&_src[1], &_dst[1] + _dst[0], _len);    \
  67.         _dst[0] += _len;                                \
  68.     } while (0)
  69. #endif
  70.  
  71. static pascal void                    ScrollLogAction(
  72.         register ControlHandle            theControl,
  73.         short                            partcode
  74.     );
  75. static void                            ScrollLogList(
  76.         ControlHandle                    theControl
  77.     );
  78.  
  79. /*
  80.  * This record is stored in the userHandle variable in the list. The values are
  81.  * needed to specify the font, limit the number of error log lines that are stored,
  82.  * and preserve the log area color. We also hide the horizontal scrollbar here
  83.  * because, if we leave it in the ListRecord, the ListManager will decide to
  84.  * permanently un-hilite it.
  85.  */
  86. typedef struct LogInfoRecord {
  87.         ControlHandle        hScroll;
  88.         short                logLines;
  89.         short                fontNumber;
  90.         short                fontSize;
  91.         RGBColor            foreColor;
  92.         RGBColor            backColor;
  93. } LogInfoRecord, *LogInfoPtr, **LogInfoHdl;
  94. #define LIST            (**logListHandle)
  95. #define LOGINFO            (**((LogInfoHdl) (LIST.userHandle)))
  96. #define HSCROLL            (LOGINFO.hScroll)
  97. #define IS_COLOR(port)    (((((CGrafPtr) (port))->portVersion) & 0xC000) != 0)
  98. #define COLOR_LIST        (IS_COLOR(LIST.port))
  99.  
  100. /*
  101.  * This code sequence is copied into the ListProc handle. It is designed so we
  102.  * don't have to flush the instruction and data caches. Note that this must
  103.  * be revised if you compile for a non-68000 environment.
  104.  */
  105. static const short gDummyLDEF[] = {
  106.         0x207A,                /*        movea.l    procPtr,a0            */
  107.         0x0004,                /*                <offset to procPtr>    */
  108.         0x4ED0,                /*        jmp        a0                     */
  109.         0x0000, 0x0000        /*        dc.l    <Drawing Proc here>    */
  110. };
  111.  
  112. static pascal void
  113. LogListDefProc(
  114.         short                    listMessage,
  115.         Boolean                    listSelect,
  116.         Rect                    *listRect,
  117.         Cell                    listCell,
  118.         short                    listDataOffset,
  119.         short                    listDataLen,
  120.         ListHandle                errorLogList
  121.     );
  122.  
  123. /*
  124.  * Create the data display list.
  125.  */
  126. ListHandle
  127. CreateLog(
  128.         const Rect                    *viewRect,
  129.         Boolean                        hasGrowBox,
  130.         short                        listFontNumber,
  131.         short                        listFontSize,
  132.         short                        logLines
  133.     )
  134. {
  135.         OSErr                        status;
  136.         ListHandle                    logListHandle;
  137.         Point                        cellSize;
  138.         Rect                        dataBounds;
  139.         Rect                        listRect;
  140.         FontInfo                    info;
  141.         short                        listHeight;
  142.         short                        listFontHeight;
  143.         Handle                        drawProcHdl;
  144.         LogInfoRecord                logInfo;
  145.         Handle                        logInfoHdl;
  146.         ProcPtr                        listProcPtr;
  147.         short                        horizontalMax;
  148.         
  149.         logInfoHdl = NULL;
  150.         drawProcHdl = NULL;
  151.         if (logLines == 0)
  152.             logLines = nDefaultLogLines;
  153.         TextFont(listFontNumber);
  154.         TextSize(listFontSize);
  155.         listRect = *viewRect;
  156.         if (hasGrowBox == FALSE) {
  157.             /*
  158.              * Since there is no growBox to align to, we can adjust the list
  159.              * rectangle so there is an integral number of lines on the list.
  160.              */
  161.             GetFontInfo(&info);
  162.             listFontHeight = info.ascent + info.descent + info.leading;
  163.             listHeight = height(listRect);
  164.             listHeight -= (listHeight % listFontHeight);
  165.             listRect.bottom = listRect.top + listHeight;
  166.         }
  167.         /*
  168.          * Note that we create a one-colum list with both vertical and horizontal
  169.          * scrollbars, then we steal the horizontal scrollbar because we're
  170.          * scrolling within the list cell. Unfortunately, the List Manager only
  171.          * scrolls from one cell (column in the horizontal direction) to another.
  172.          */
  173.         SetPt(&cellSize, 0, 0);
  174.         SetRect(&dataBounds, 0, 0, 1, 0);
  175.         logListHandle = LNew(
  176.                 &listRect,                            /* Viewing area                */
  177.                 &dataBounds,                        /* Rows and col's            */
  178.                 cellSize,                            /* Element size                */
  179.                 0,                                    /* No defProc yet            */
  180.                 qd.thePort,                            /* Display window            */
  181.                 TRUE,                                /* Draw it                    */
  182.                 hasGrowBox,                            /* User's choice            */
  183.                 TRUE,                                /* Has horizontal scroll    */
  184.                 TRUE                                /* Has vertical scroll        */
  185.             );
  186.         if (logListHandle == NULL)
  187.             goto failure;
  188.         LIST.selFlags = lOnlyOne;
  189.         LIST.listFlags = lDoVAutoscroll;            /* Vertical autoscroll only    */
  190.         logInfo.logLines = logLines;
  191.         logInfo.fontNumber = listFontNumber;
  192.         logInfo.fontSize = listFontSize;
  193.         if (COLOR_LIST) {
  194.             GetForeColor(&logInfo.foreColor);
  195.             GetBackColor(&logInfo.backColor);
  196.         }
  197.         status = PtrToHand(&logInfo, &logInfoHdl, sizeof logInfo);
  198.         if (status != noErr)
  199.             goto failure;
  200.         LIST.userHandle = (Handle) logInfoHdl;
  201.         HSCROLL = LIST.hScroll;                        /* Grab horizontal scroller    */
  202.         LIST.hScroll = NULL;                        /* Remove it from the list    */
  203.         SetCRefCon(HSCROLL, (long) logListHandle);    /* Link scrollbar to list    */
  204.         status = PtrToHand(gDummyLDEF, &drawProcHdl, sizeof gDummyLDEF);
  205.         if (status != noErr)
  206.             goto failure;
  207.         listProcPtr = (ProcPtr) LogListDefProc;
  208.         BlockMove(&listProcPtr, &((short *) *drawProcHdl)[3], sizeof listProcPtr);
  209.         LIST.listDefProc = drawProcHdl;
  210.         horizontalMax = kMaxHorizontalScroll - width((**HSCROLL).contrlRect);
  211.         if (horizontalMax < 0)
  212.             horizontalMax = 0;
  213.         SetCtlMin(HSCROLL, 0);
  214.         SetCtlMax(HSCROLL, horizontalMax);
  215.         SetCtlValue(HSCROLL, 0);
  216.         if (horizontalMax == 0)
  217.             HiliteControl(HSCROLL, kDisabledControl);
  218.         goto success;
  219. failure:
  220.         if (drawProcHdl != NULL) {
  221.             DisposeHandle((Handle) drawProcHdl);
  222.             LIST.listDefProc = NULL;
  223.         }
  224.         DisposeLog(logListHandle);
  225.         logListHandle = NULL;
  226. success:
  227.         return (logListHandle);
  228. }
  229.  
  230. /*
  231.  * DisposeLog disposes of our private information and then disposes of the list.
  232.  */
  233. void
  234. DisposeLog(
  235.         ListHandle                        logListHandle
  236.     )
  237. {
  238.         if (logListHandle != NULL) {
  239.             if (LIST.userHandle != NULL) {
  240.                 LIST.hScroll = HSCROLL;            /* The list manager disposes    */ 
  241.                 DisposeHandle(LIST.userHandle);
  242.                 LIST.userHandle = NULL;
  243.             }
  244.             LDispose(logListHandle);
  245.         }
  246. }
  247.  
  248. /*
  249.  * UpdateLog redraws the list.
  250.  */
  251. void
  252. UpdateLog(
  253.         ListHandle                        logListHandle
  254.     )
  255. {
  256.         Rect                        viewRect;
  257.         RGBColor                    saveForeColor;
  258.         RGBColor                    saveBackColor;
  259.         
  260.         if (logListHandle != NULL) {
  261.             /*
  262.              * Make sure the list is locked down while we draw. Note that we
  263.              * assume that the application has called UpdateControls, so
  264.              * the horizontal scrollbar is correctly drawn.
  265.              */        
  266.             if (COLOR_LIST) {
  267.                 GetForeColor(&saveForeColor);
  268.                 GetBackColor(&saveBackColor);
  269.                 RGBForeColor(&LOGINFO.foreColor);
  270.                 RGBBackColor(&LOGINFO.backColor);
  271.             }
  272.             viewRect = LIST.rView;
  273.             /*
  274.              * Include the scrollbars in the frame.
  275.              */
  276.             EraseRect(&viewRect);
  277.             InsetRect(&viewRect, -1, -1);
  278.             viewRect.right += kScrollBarOffset;
  279.             viewRect.bottom += kScrollBarOffset;
  280.             FrameRect(&viewRect);
  281.             LUpdate(LIST.port->visRgn, logListHandle);
  282.             if (COLOR_LIST) {
  283.                 RGBForeColor(&saveForeColor);
  284.                 RGBBackColor(&saveBackColor);
  285.             }
  286.         }
  287. }
  288.  
  289. /*
  290.  * ActivateLog activates (or deactivates) the log. Call it on activate and
  291.  * suspendResume events.
  292.  */
  293. void
  294. ActivateLog(
  295.         ListHandle                        logListHandle,
  296.         Boolean                            activating
  297.     )
  298. {
  299.         if (logListHandle != NULL) {
  300.             LActivate(activating, logListHandle);
  301.             HiliteControl(
  302.                 HSCROLL,
  303.                 (activating) ? kActiveControl : kDisabledControl);
  304.         }
  305. }
  306.  
  307. /*
  308.  * MoveLog Repositions the log list area.
  309.  */
  310. void
  311. MoveLog(
  312.         ListHandle                        logListHandle,
  313.         short                            leftEdge,
  314.         short                            topEdge
  315.     )
  316. {
  317.         Rect                            viewRect;
  318.         
  319.         if (logListHandle != NULL) {
  320.             if (LIST.rView.left != leftEdge || LIST.rView.top != topEdge) {
  321.                 viewRect = LIST.rView;
  322.                 InsetRect(&viewRect, -1, -1);
  323.                 InvalRect(&viewRect);
  324.                 OffsetRect(
  325.                     &LIST.rView,
  326.                     leftEdge - LIST.rView.left,
  327.                     topEdge -LIST.rView.top
  328.                 );
  329.                 viewRect = LIST.rView;
  330.                 InsetRect(&viewRect, -1, -1);
  331.                 InvalRect(&viewRect);
  332.                 MoveControl(
  333.                     LIST.vScroll,
  334.                     LIST.rView.right - kScrollBarOffset,
  335.                     LIST.rView.top - 1
  336.                 );
  337.                 MoveControl(
  338.                     HSCROLL,
  339.                     LIST.rView.left - 1,
  340.                     LIST.rView.bottom - kScrollBarOffset
  341.                 );
  342.             }
  343.         }
  344. }
  345.  
  346. /*
  347.  * SizeLog: this is the list rectangle size and does not include the
  348.  * horizontal and vertical scrollbars.
  349.  */
  350. void
  351. SizeLog(
  352.         ListHandle                        logListHandle,
  353.         short                            newWidth,
  354.         short                            newHeight
  355.     )
  356. {
  357.         Rect                            viewRect;
  358.         Point                            cellSize;
  359.         short                            horizontalMax;
  360.         
  361.         if (logListHandle != NULL) {
  362.             viewRect = LIST.rView;
  363.             InsetRect(&viewRect, -1, -1);
  364.             InvalRect(&viewRect);
  365.             /*
  366.              * We put the horizontal scrollbar back into the list record so that
  367.              * the list manager kindly resizes it. Then we take it out again.
  368.              */
  369.             LIST.hScroll = HSCROLL;
  370.             LSize(newWidth, newHeight, logListHandle);
  371.             LIST.hScroll = NULL;
  372.             cellSize = LIST.cellSize;
  373.             cellSize.h = width(LIST.rView);
  374.             LCellSize(cellSize, logListHandle);
  375.             horizontalMax = kMaxHorizontalScroll - width((**HSCROLL).contrlRect);
  376.             if (horizontalMax < 0)
  377.                 horizontalMax = 0;
  378.             SetCtlMax(HSCROLL, horizontalMax);
  379.             HiliteControl(
  380.                 HSCROLL,
  381.                 (horizontalMax == 0) ? kDisabledControl : kActiveControl
  382.             );
  383.             viewRect = LIST.rView;
  384.             InsetRect(&viewRect, -1, -1);
  385.             InvalRect(&viewRect);
  386.         }
  387. }
  388.  
  389. /*
  390.  * DoClickInLog: call this when there is a mouse down in the log area (or in
  391.  * one of the scrollbars.
  392.  */
  393. Boolean
  394. DoClickInLog(
  395.         ListHandle                        logListHandle,
  396.         const EventRecord                *eventRecord
  397.     )
  398. {
  399. #define EVENT    (*eventRecord)
  400.  
  401.         Point                            mousePt;
  402.         Boolean                            result;
  403.         Rect                            viewRect;
  404.         short                            part;
  405.         ControlHandle                    theControl;
  406.  
  407.         if (logListHandle == NULL)
  408.             result = FALSE;
  409.         else {
  410.             mousePt = EVENT.where;
  411.             GlobalToLocal(&mousePt);
  412.             /*
  413.              * Handle clicks in the horizontal scrollbar:Do not pass them through
  414.              * LClick, as it does not do what we want and besides, the scrollbar
  415.              * isn't there any more.
  416.              */
  417.             if (PtInRect(mousePt, &(**HSCROLL).contrlRect)) {
  418.                 part = FindControl(mousePt, (**HSCROLL).contrlOwner, &theControl);
  419.                 if (part >= 0 && theControl == HSCROLL) {
  420.                     if (part == inThumb) {
  421.                         if (TrackControl(theControl, mousePt, NULL))
  422.                             ScrollLogList(theControl);
  423.                     }
  424.                     else {
  425.                         TrackControl(theControl, mousePt, (ProcPtr) ScrollLogAction);
  426.                     }
  427.                 }
  428.             }
  429.             else {
  430.                 viewRect = LIST.rView;
  431.                 viewRect.right += kScrollBarOffset;
  432.                 if ((result = PtInRect(mousePt, &viewRect)))
  433.                     (void) LClick(mousePt, EVENT.modifiers, logListHandle);
  434.             }
  435.         }
  436.         return (result);
  437. #undef EVENT
  438. }
  439.  
  440. /*
  441.  * Log errors.
  442.  */
  443. void
  444. LogStatus(
  445.         ListHandle                        logListHandle,
  446.         OSErr                            theError,
  447.         const StringPtr                    infoText
  448.     )
  449. {
  450.         Handle                            macErrorHdl;
  451.         Str255                            msg;
  452.         Str15                            errorValue;
  453.         
  454.         if (logListHandle != NULL && theError != noErr) {
  455.             pstrcpy(msg, infoText);
  456.             pstrcat(msg, "\p: ");
  457.             NumToString(theError, errorValue);
  458.             pstrcat(msg, errorValue);
  459.             macErrorHdl = GetResource('Estr', theError);
  460.             if (macErrorHdl != NULL) {
  461.                 pstrcat(msg, "\p ");
  462.                 pstrcat(msg, (StringPtr) *macErrorHdl);
  463.                 ReleaseResource(macErrorHdl);
  464.             }
  465.             DisplayLogString(logListHandle, msg);
  466.         }
  467. }
  468.  
  469. /*
  470.  * DisplayLogString
  471.  * Call this function to store a string in the list.
  472.  */
  473. void
  474. DisplayLogString(
  475.         ListHandle                        logListHandle,
  476.         const StringPtr                    theString
  477.     )
  478. {
  479.  
  480.         Cell                        theCell;
  481.         short                        theRow;
  482.         Boolean                        scrollAtBottom;
  483.         
  484.         if (logListHandle != NULL) {
  485.             /*
  486.              * If there are already logLines in the
  487.              * list, delete the first row of the list.
  488.              * Then, in any case, append this datum at the
  489.              * bottom.
  490.              *
  491.              * The scroll bars are managed as follows:
  492.              * scroll bar is at the bottom, the new datum
  493.              * is selected and autoscrolled into view.
  494.              * Otherwise, the current cell is unchanged.
  495.              */
  496.             theRow = LIST.dataBounds.bottom;
  497.             scrollAtBottom =
  498.                 (GetCtlValue(LIST.vScroll) == GetCtlMax(LIST.vScroll));
  499.             if (theRow >= LOGINFO.logLines)
  500.                 LDelRow(1, 0, logListHandle);
  501.             theRow = LAddRow(1, LIST.dataBounds.bottom, logListHandle);
  502.             if (MemError() != noErr)
  503.                 goto failure;
  504.             theCell.h = 0;
  505.             theCell.v = theRow;
  506.             LSetCell((Ptr) &theString[1], theString[0], theCell, logListHandle);
  507.             if (MemError() != noErr)
  508.                 goto failure;
  509.             if (scrollAtBottom) {
  510.                 theCell.v = 0;
  511.                 if (LGetSelect(TRUE, &theCell, logListHandle))
  512.                     LSetSelect(FALSE, theCell, logListHandle);
  513.                 theCell.v = theRow;
  514.                 LSetSelect(TRUE, theCell, logListHandle);
  515.                 LDoDraw(TRUE, logListHandle);
  516.                 LAutoScroll(logListHandle);
  517.             }
  518.             LDraw(theCell, logListHandle);
  519.         }
  520. failure:
  521.         return;
  522. }
  523.  
  524. /*
  525.  * ScrollLogAction is called by the Toolbox while executing the TrackControl
  526.  * routine.  It has to take care of scrolling the log when the user clicks on the
  527.  * up/down arrow or page parts of the scroll bar.
  528.  */
  529. static pascal void
  530. ScrollLogAction(
  531.         register ControlHandle            theControl,
  532.         short                            partcode
  533.     )
  534. {
  535.         short                            delta;
  536.         
  537.         delta = (width((**theControl).contrlRect) * 7) / 8;
  538.         switch (partcode) {
  539.         case inUpButton:    delta = -CharWidth('M');    break;
  540.         case inPageUp:        delta = -(delta);            break;        
  541.         case inDownButton:    delta = CharWidth('M');        break;
  542.         case inPageDown:    /* All set */                break;
  543.         default:            return;        /* Mouse exited control    */
  544.         }
  545.         SetCtlValue(theControl, GetCtlValue(theControl) + delta);
  546.         ScrollLogList(theControl);
  547. }
  548.  
  549. /*
  550.  * ScrollLogList scrolls the list rectangle in the proper direction and updates
  551.  * the list's horizontal indentation to match.
  552.  */
  553. static void
  554. ScrollLogList(
  555.         ControlHandle                    theControl
  556.     )
  557. {
  558.         ListHandle                        logListHandle;
  559.         short                            delta;
  560.         RgnHandle                        clipRgn;
  561.         RgnHandle                        updateRgn;
  562.         Rect                            viewRect;
  563.         
  564.         logListHandle = (ListHandle) GetCRefCon(theControl);
  565.         /*
  566.          * LIST.indent.h is negative when the cell is scrolled left. Get the
  567.          * amount it's currently scrolled (as a positive value) and set delta
  568.          * to the amount that must be scrolled. Delta will be positive to
  569.          * scroll right (which means that the scrollbar has moved left).
  570.          */
  571.         delta = kZeroIndent - LIST.indent.h - GetCtlValue(theControl);
  572.         if (delta != 0) {
  573.             /*
  574.              * We need to scroll the list cells. Get a clip rectangle so the
  575.              * scrolling is limited to the drawing area, scroll it, and update
  576.              * the stuff that came into view.
  577.              */
  578.             viewRect = LIST.rView;
  579.             clipRgn = NewRgn();
  580.             updateRgn = NewRgn();
  581.             GetClip(clipRgn);
  582.             ClipRect(&viewRect);
  583.             ScrollRect(&viewRect, delta, 0, updateRgn);
  584.             LIST.indent.h += delta;
  585.             LUpdate(updateRgn, logListHandle);
  586.             SetClip(clipRgn);
  587.             DisposeRgn(updateRgn);
  588.             DisposeRgn(clipRgn);
  589.         }
  590. }
  591.         
  592. /*
  593.  * Draw the string stored in the list. The only difference between this function
  594.  * and a "normal" LDEF is that we don't visually indicate selection.
  595.  */
  596. static pascal void
  597. LogListDefProc(
  598.         short                            listMessage,
  599.         Boolean                            listSelect,
  600.         Rect                            *listRect,
  601.         Cell                            listCell,
  602.         short                            listDataOffset,
  603.         short                            listDataLen,
  604.         ListHandle                        logListHandle
  605.     )
  606. {
  607. #pragma unused (listCell)
  608.  
  609.         Boolean                            cellLockState;
  610.         RGBColor                        saveForeColor;
  611.         RGBColor                        saveBackColor;
  612.         
  613.         /*
  614.          * If the userHandle isn't setup, do nothing: this is an initialization
  615.          * or a spurious command while we're disposing of the list.
  616.          */
  617.         if (LIST.userHandle != NULL) {
  618.             TextFont(LOGINFO.fontNumber);
  619.             TextSize(LOGINFO.fontSize);
  620.             if (COLOR_LIST) {
  621.                 GetForeColor(&saveForeColor);
  622.                 GetBackColor(&saveBackColor);
  623.                 RGBForeColor(&LOGINFO.foreColor);
  624.                 RGBBackColor(&LOGINFO.backColor);
  625.             }
  626.             switch (listMessage) {
  627.             case lInitMsg:
  628.                 break;
  629.             case lDrawMsg:
  630.                 EraseRect(listRect);
  631.                 if (listDataLen > 0) {
  632.                     /*
  633.                      * We don't indent in the vertical direction: by default,
  634.                      * it contains the font ascent which is fine for DrawText
  635.                      */
  636.                     cellLockState = HGetState(LIST.cells);
  637.                     HLock(LIST.cells);
  638.                     MoveTo(
  639.                         listRect->left + LIST.indent.h,
  640.                         listRect->top + LIST.indent.v
  641.                     );
  642.                     DrawText((Ptr) (*LIST.cells), listDataOffset, listDataLen);
  643.                     HSetState(LIST.cells, cellLockState);
  644.                 }
  645.                 if (listSelect == FALSE)
  646.                     break;
  647.                 /* Continue to do hilite */
  648.             case lHiliteMsg:
  649. #if 0        /* Hiliting is disabled */
  650. #ifdef THINK_C
  651.                 HiliteMode &= ~(1 << hiliteBit);
  652. #else /* MPW */
  653.                 *((char *) HiliteMode) &= ~(1 << hiliteBit); /* Inside Mac V-61    */
  654. #endif
  655.                 InvertRect(listRect);
  656. #endif
  657.                 break;
  658.             }
  659.             if (COLOR_LIST) {
  660.                 RGBForeColor(&saveForeColor);
  661.                 RGBBackColor(&saveBackColor);
  662.             }
  663.         }
  664. }
  665.  
  666.